package cn.virens.service.impl.pay;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;

import cn.hutool.core.util.StrUtil;
import cn.virens.common.MapUtil;
import cn.virens.database.common.TransactionExecute;
import cn.virens.exception.APIException;
import cn.virens.service.inter.pay.AlipayService;

@Service
public class AlipayServiceImpl implements AlipayService, InitializingBean {
	private final Logger logger = LoggerFactory.getLogger(getClass());

	private @Autowired TransactionExecute mTransactionExecute;

	private AliPayApiConfig payApiConfig;

	@Value("${alipay.privatekey}")
	private String privateKey;

	@Value("${alipay.publickey}")
	private String publicKey;

	@Value("${alipay.serverurl}")
	private String serverUrl;

	@Value("${alipay.signtype}")
	private String signType;

	@Value("${alipay.charset}")
	private String charset;

	@Value("${alipay.appid}")
	private String appId;

	@Value("${alipay.showname}")
	private String showname;

	@Value("${alipay.url.return}")
	private String returnUrl;

	@Value("${alipay.url.notifly}")
	private String notifyUrl;

	@Override
	public boolean notify(Map<String, String> params) throws APIException {
		return mTransactionExecute.write((s) -> exec(() -> {
			// 验证消息签名-----------------------------------------------------------------------------------
			if (!AlipaySignature.rsaCheckV1(params, publicKey, charset, signType)) {//
				throw new APIException("ERROR", "签名验证失败");
			}

			// 验证通知消息来源--------------------------------------------------------------------------------
			if (!StrUtil.equals(appId, params.get("app_id"))) {//
				throw new APIException("ERROR", "来源异常");
			}

			// 获取订单状态
			String tradeStatus = MapUtil.getString(params, "trade_status");

			// 判断支付是否成功 & 成功后更新订信息----------------------------------------------------------------
			if (StrUtil.equals(tradeStatus, "WAIT_BUYER_PAY")) {
				logger.debug("支付宝异步回调通知（交易创建）：" + JSON.toJSONString(params));
			} else if (StrUtil.equals(tradeStatus, "TRADE_FINISHED")) {
				logger.debug("支付宝异步回调通知（交易完结）：" + JSON.toJSONString(params));
			} else if (StrUtil.equals(tradeStatus, "TRADE_SUCCESS")) {
				// TODO 更新订单状态-交易成功
			} else if (StrUtil.equals(tradeStatus, "TRADE_CLOSED")) {
				// TODO 更新订单状态-交易失败
			} else {
				throw new APIException("UNKOWN", "状态未知");
			}

			return true;
		}));
	}

	@Override
	public String pay(String orderNo, String subject) throws APIException {
		return mTransactionExecute.write((s) -> exec(() -> {
			// TODO 查询订单信息

			// 构建支付宝WAP支付订单数据模型--------------------------------------------------------------------
			AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
			//			model.setPassbackParams(URLUtil.encode(record.getParams()));
			//			model.setTotalAmount(format(record.getMoney()));
			//			model.setOutTradeNo(record.getOrderNo());
			//			model.setBody(record.getBody());

			model.setProductCode("QUICK_WAP_PAY");
			model.setSubject(subject);

			// 构建支付回调地址 & 通知地址
			String url1 = url(returnUrl, orderNo);
			String url2 = url(notifyUrl, orderNo);

			// 执行支付宝支付签名
			return AliPayApi.wapPayStr(model, url1, url2);
		}));
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.payApiConfig = AliPayApiConfig.builder();
		this.payApiConfig.setAliPayPublicKey(publicKey);
		this.payApiConfig.setPrivateKey(privateKey);
		this.payApiConfig.setServiceUrl(serverUrl);
		this.payApiConfig.setSignType(signType);
		this.payApiConfig.setCharset(charset);
		this.payApiConfig.setAppId(appId);
		this.payApiConfig.build();
	}

	private static String url(String src, String order) {
		return StrUtil.replace(src, "_order_", order);
	}

	protected <T> T exec(AlipayExec<T> alipayExec) throws APIException {
		AliPayApiConfigKit.setThreadLocalAliPayApiConfig(payApiConfig);
		AliPayApiConfigKit.setThreadLocalAppId(appId);

		try {
			return alipayExec.exec();
		} catch (AlipayApiException e) {
			throw new APIException(e.getErrCode(), e.getErrMsg());
		} catch (Exception e) {
			throw new APIException(e);
		}
	}

	protected interface AlipayExec<T> {
		T exec() throws Exception;
	}

}
